package com.spring.core.bean;

import annotation.AfterReturning;
import annotation.Aspect;

import annotation.Before;
import aop.AdvisedSupport;
import aop.AopProxy;
import com.spring.core.context.AbstractApplicationContext;
import com.spring.util.StringUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * @author Zee
 * @version 1.0
 * @date 2021/10/13
 */
public class AopBean extends AbstractBean {


    @Override
    public void init(AbstractApplicationContext context) {
        System.out.println("初始化Aop: @Aspect JDK代理,Cglib代理...");
        for (String className : context.getClassNames()) {
            try {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Aspect.class)) {
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(AfterReturning.class)) {
                            AfterReturning afterReturning = method.getAnnotation(AfterReturning.class);
                            initAopProxy(context, afterReturning.value(), method, context.getClassNames());
                        }
                        if (method.isAnnotationPresent(Before.class)) {
                            Before before = method.getAnnotation(Before.class);
                            initAopProxy(context, before.value(), method, context.getClassNames());
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

    }

    private void initAopProxy(AbstractApplicationContext context, String value, Method supportMethod, List<String> classNames) {
        String methodTypeName = supportMethod.getDeclaringClass().getSimpleName();
        for (String className : classNames) {
            Class<?> clazz;
            try {
                clazz = Class.forName(className);
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (value.contains("@")) {
                        Annotation[] annotations = method.getAnnotations();
                        for (int i = 0; i < annotations.length; i++) {
                            String annotationName = annotations[i].annotationType().getSimpleName();
                            if (value.contains(annotationName)) {
                                String beanName = clazz.getSimpleName();
                                Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new AopProxy(new AdvisedSupport(supportMethod, context.getBean(beanName), context.getBean(methodTypeName),value)));
                                context.putBean(beanName, obj);
                                break;
                            }
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }

    }
}